package com.zktravel.util;

import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.util.Assert;

import com.odianyun.util.date.DateUtils;
import com.odianyun.util.net.IPUtils;

public class CodeGenerator {
	private final static CodeGenerator INST = new CodeGenerator();
	
	public static CodeGenerator getInstance() {
		return INST;
	}
	
	private AtomicLong lastGenerateTime = new AtomicLong();
	
	private CodeGenerator() {}

	public String[] generate(String prefix, int length, int size) {
		synchronized (prefix) {
			checkAndSleep();
			return doGenerate(prefix, length, size);
		}
	}
	
	private String[] doGenerate(String prefix, int length, int size) {
		int numberPart = length - prefix.length();
		
		Assert.isTrue(numberPart > 16, "生成编码至少" + (numberPart + prefix.length()) + "位以上");
		
		String ipPart = getIp();
		String timePart = DateUtils.date2Str(new Date(), "yyMMddHHmmss");
		int randomPartLength = numberPart - ipPart.length() - timePart.length();
		
		int maxRandomSize = (int) Math.pow(10, randomPartLength);

		String[] randomParts = new String[size];
		
		if (size > maxRandomSize) {
			int pos = 0;
			
			int split = size / maxRandomSize + (size % maxRandomSize > 0 ? 1 : 0);
			int batch = maxRandomSize;
			
			for (int i=0; i<split; i++) {
				checkAndSleep();
				
				if (batch > randomParts.length - pos) {
					batch = randomParts.length - pos;
				}
				String[] ss = getRandomParts(batch, randomPartLength, maxRandomSize);
				System.arraycopy(ss, 0, randomParts, pos, batch);
				
				pos += maxRandomSize;
				
				if (pos > size) batch = size % maxRandomSize;
			}
		} else {
			randomParts = getRandomParts(size, randomPartLength, maxRandomSize);
		}
		
		String[] codes = new String[size];
		
		for (int i=0; i<size; i++) {
			codes[i] = prefix + timePart + ipPart + randomParts[i];
		}
		
		return codes;
	}
	
	private String[] getRandomParts(int size, int randomPartLength, int maxRandomSize) {
		Random random = new Random();
		
		Set<Integer> checkRepeat = new HashSet<Integer>(size);
		
		String[] codes = new String[size];
		
		for (int i=0; i<size; i++) {
			int r = random.nextInt(maxRandomSize);
			
			while (checkRepeat.contains(r)) {
				r = random.nextInt(maxRandomSize);
			}
			
			checkRepeat.add(r);

			String randomPart = padding(r+"", "0", randomPartLength);
			
			codes[i] = randomPart;
		}
		
		lastGenerateTime.set(System.currentTimeMillis());
		return codes;
	}
	
	private boolean checkAndSleep() {
		Long now = System.currentTimeMillis();
		
		long _lastGeneratorTime = lastGenerateTime.get();
		
		//最后执行时间小于1秒线程就睡一秒
		if (_lastGeneratorTime != 0L && (now - _lastGeneratorTime) < 1000) {
			try {
				Thread.sleep(1000L);
				return true;
			} catch (Exception ignore) {
				// do nothing
			}
		}
		return false;
	}
	
	private String padding(String s, String padding, int length) {
		StringBuilder buff = new StringBuilder();
		for (int i=s.length(); i<length; i++) {
			buff.append(padding);
		}
		buff.append(s);
		return buff.toString();
	}
	
	//得到本地IP三位数
	private String getIp() {
		String localIp = IPUtils.getAnyLocalIP();
		String m = localIp.substring(localIp.lastIndexOf(".") + 1);
		if (m.length() == 1) return "00" + m;
		if (m.length() == 2) return "0" + m;
		return m;
	}
	
}
